home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
comm
/
misc
/
xqsrc1_7.lzh
/
library
/
file.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-12
|
11KB
|
516 lines
/*
* Name: file.c
*
* Description: File related functions for xferq.library
*
* Copyright: 1992-1993 by David Jones.
*
* Distribution:
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
*
* The Free Software Foundation David Jones
* 675 Mass Ave 6730 Tooney Drive
* Cambridge, MA Orleans, Ontario
* 02139 K1C 6R4
* USA Canada
*
* Usenet: gnu@prep.ai.mit.edu aa457@freenet.carleton.ca
* Fidonet: 1:163/109.8
*
* $Log: $
*
*/
#include <exec/types.h>
#include <execlists.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <string.h>
#include "xferq.h"
#include "xferqint.h"
#include "xferq_pragmas.h"
extern BOOL QueueScanned;
extern struct NetAddress *DefaultAddr;
char *FidoName = "_$(DOMAIN:S).$(ZONE:D).$(NET:D).$(NODE:D).$(POINT:D).queue";
char *UucpName = "_UUCP.$(UUCPNAME:S).queue";
char *TextName = "_TEXT.$(TEXTNAME:S).queue";
BOOL ConfigRead;
char *MakeFileName(struct NetAddress *addr)
/*
* In: addr Address to make filename for
*
* Does: Constructs the filename for a queue file given the address.
*
*/
{
struct VarList *vl;
char *template, *filename;
#ifdef DEBUG
int count = GetCount(addr);
#endif
switch (addr->type) {
case XQNT_FIDO:
template = FidoName;
break;
case XQNT_UUCP:
template = UucpName;
break;
case XQNT_TEXT:
template = TextName;
break;
default:
return NULL;
}
vl = NewVarList();
if (!vl) {
return NULL;
}
if (ExamObjectVarList(addr, vl)) {
filename = MakeString(NULL, template, vl);
}
else {
filename = NULL;
}
DropVarList(vl);
#ifdef DEBUG
CheckCount("MakeFileName", addr, count);
#endif
return filename;
}
ULONG __saveds __asm LIBNextSeq(void)
/*
* Does: Returns a unique 32-bit sequence number each time the function
* is called. The numbers will repeat after 2^32 calls.
*/
{
return 0;
}
ULONG TruncateFile(char *name)
/*
* In: name Name of file to truncate
*
* Does: The file is given zero length, although it still exists.
* The function returns the appropriate XfqRemoveWork() code.
*/
{
BPTR fh;
fh = Open(name, MODE_OLDFILE);
if (fh) {
SetFileSize(fh, OFFSET_BEGINNING, 0);
Close(fh);
return XQRM_TRUNCATED;
}
else {
Error(XQERROR_DOS);
return XQRM_ERROR;
}
}
char *FullPath(char *name)
/*
* In: name Name to take full path of
*
* Does: Returns a string object which is the fully-qualified path name
* of the input.
*/
{
char buf[258];
int i, len;
BPTR lock;
BOOL rc;
len = strlen(name);
for (i = 0; i < len; i++) {
if (name[i] == ':') {
return CopyString(name);
}
}
lock = Lock(name, ACCESS_READ);
if (lock) {
rc = NameFromLock(lock, buf, sizeof(buf));
UnLock(lock);
if (rc) {
return CopyString(buf);
}
else {
Error(XQERROR_DOS);
return NULL;
}
}
Error(XQERROR_DOS);
return NULL;
}
BOOL ReadQueueContents(BPTR file, struct SiteNode *sn)
/*
* In: file File containing contents of queue.
* sn Site node to read into.
*
* Does: Reads the contents of the file, forming the entries for the
* site queue. The function returns TRUE on success, FALSE
* otherwise.
*/
{
char line[260];
struct WorkNode *wn;
long n, len;
char *cp;
while (FGets(file, line, sizeof(line))) {
wn = XfqCreateObject(XQO_WORKNODE, NULL);
if (!wn) {
DropSiteNode(sn);
return FALSE;
}
while (line[0] != '#') {
switch (line[0]) {
case 'F':
len = strlen(line) - 2; /* Drop header and newline */
wn->node.ln_Name = CopyStringN(&line[1], len);
if (!wn->node.ln_Name) {
#ifdef DEBUG
kprintf("No mem for name\n");
#endif
XfqDropObject(wn);
DropSiteNode(sn);
return FALSE;
}
break;
case 'A':
len = strlen(line) - 2; /* Drop header and newline */
wn->asname = CopyStringN(&line[1], len);
if (!wn->asname) {
#ifdef DEBUG
kprintf("No mem for asname\n");
#endif
XfqDropObject(wn);
DropSiteNode(sn);
return FALSE;
}
break;
case 'P':
cp = &line[1];
GetNumber(cp, 10, 0, &n);
wn->node.ln_Pri = n;
break;
case 'C':
cp = &line[1];
GetNumber(cp, 10, 0, &n);
wn->userFlags = n;
break;
case 'S':
cp = &line[1];
GetNumber(cp, 10, 0, &n);
wn->status = n;
break;
}
if (!FGets(file, line, sizeof(line)) && IoErr()) {
#ifdef DEBUG
kprintf("Tail fail %d\n", IoErr());
#endif
Error(XQERROR_DOS);
DropSiteNode(sn);
return FALSE;
}
} /* while != '#' */
/*
* Can't use AddWork() cuz that will recurse!
*/
XfqCopyObject(sn->site);
wn->site = sn;
wn->addr = sn->site;
wn->sysFlags = XQ_INQUEUE;
ADDHEAD(&sn->workList, wn);
} /* while not EOF or error*/
if (IoErr()) {
#ifdef DEBUG
kprintf("Done fail %d\n", IoErr());
#endif
Error(XQERROR_DOS);
DropSiteNode(sn);
return FALSE;
}
sn->flags &= ~XQSITE_UNREAD;
#ifdef DEBUG
kprintf("Read in OK\n");
#endif
return TRUE;
}
void ReadQueue(struct SiteNode *sn)
/*
* In: sn Site node to read queue for
*
* Does: Reads the queue file from disk.
*
*/
{
char *name;
BPTR cdLock, oldLock;
BPTR file;
BOOL readOk;
LONG ioErr;
cdLock = Lock("XFERQ:", SHARED_LOCK);
if (!cdLock) {
Error(XQERROR_DOS);
return;
}
oldLock = CurrentDir(cdLock);
name = MakeFileName(sn->site);
#ifdef DEBUG
kprintf("Reading %s\n", name);
#endif
if (name) {
file = Open(&name[1], MODE_OLDFILE);
if (file) {
readOk = ReadQueueContents(file, sn);
ioErr = IoErr();
Close(file);
if (readOk) {
/* Delete _file if file exists and was read in OK. */
DeleteFile(name);
}
if (!ioErr) {
/* Error was due to memory problem -> fail */
goto endread;
}
}
file = Open(name, MODE_OLDFILE);
if (file) {
ReadQueueContents(file, sn);
Close(file);
if (readOk) {
/*
* New file was OK so move it over.
* If old file exists, but was corrupted, then this
* will fail. Human intervention is probably
* required here. For further study.
*/
Rename(name, &name[1]);
}
}
}
endread:
XfqDropObject(name);
CurrentDir(oldLock);
UnLock(cdLock);
}
BOOL WriteQueue(struct ExtSessWalk *esw)
/*
* In: addr Address to write queue for
*
* Does: Writes the queue file to disk.
*
*/
{
char *name;
BPTR fh;
BPTR cdLock, oldLock;
struct WorkNode *wn;
struct SiteNode *sn;
sn = esw->sn;
if (!(sn->flags & XQSITE_DIRTY)) {
return TRUE;
}
cdLock = Lock("XFERQ:", SHARED_LOCK);
if (!cdLock) {
Error(XQERROR_DOS);
return FALSE;
}
name = MakeFileName(sn->site);
if (!name) {
return FALSE;
}
oldLock = CurrentDir(cdLock);
wn = FIRST(&sn->workList);
if (!NEXT(wn)) {
DeleteFile(&name[1]);
sn->flags &= ~XQSITE_DIRTY;
}
else {
fh = Open(name, MODE_NEWFILE);
if (fh) {
while (NEXT(wn)) {
/*
* If IMMEDIATE is in effect, then anything that can cause
* the queue to be read in also nukes any sessions that
* were up so don't even bother to write these out.
*
* Similar logic goes for SENDLATER, but this time we
* must clear the SENDLATER bit.
*/
if (!(wn->userFlags & XQ_IMMEDIATE)) {
FPrintf(fh, "F%s\n", wn->node.ln_Name);
if (wn->asname) {
FPrintf(fh, "A%s\n", wn->asname);
}
FPrintf(fh, "P%ld\n", wn->node.ln_Pri);
FPrintf(fh, "C%ld\n", wn->userFlags & ~XQ_SENDLATER);
FPrintf(fh, "S%ld\n", wn->status);
FPrintf(fh, "#\n", NULL);
}
wn = NEXT(wn);
}
sn->flags &= ~XQSITE_DIRTY;
Close(fh);
DeleteFile(&name[1]);
Rename(name, &name[1]);
}
else {
Error(XQERROR_DOS);
}
}
CurrentDir(oldLock);
UnLock(cdLock);
return TRUE;
}
void ScanQueue(void)
/*
* Does: Scans the queue directory for queue files. For each queue file
* found, it creates a site node and marks it as unread.
*/
{
BPTR cdLock, oldLock;
struct NetAddress *na;
struct SiteNode *sn;
struct AnchorPath *ap;
struct VarList *vl;
long error, type;
char *name;
cdLock = Lock("XFERQ:", SHARED_LOCK);
if (!cdLock) {
Error(XQERROR_DOS);
return;
}
oldLock = CurrentDir(cdLock);
ap = AllocObject(sizeof(struct AnchorPath), XQO_APATH);
vl = NewVarList();
if (ap && vl) {
ap->ap_Strlen = 0;
ap->ap_BreakBits = 0;
ap->ap_Flags = 0;
error = MatchFirst("#?.queue", ap);
while (!error) {
name = ap->ap_Info.fib_FileName;
if (name[0] == '_') {
name++; /* File is in error recovery mode. */
}
if (ScanString(name, &FidoName[1], vl)) {
type = XQNT_FIDO;
}
else if (ScanString(name, &UucpName[1], vl)) {
type = XQNT_UUCP;
}
else if (ScanString(name, &TextName[1], vl)) {
type = XQNT_TEXT;
}
else {
type = 0; /* unknown type - ignore */
}
if (type) {
na = XfqCreateObjectTags(XQO_ADDRESS,
XQ_Network, type,
TAG_DONE);
if (na) {
na = ModifyObjectVarList(na, vl);
}
EmptyVarList(vl);
if (na) {
sn = NewSiteQueue(na);
XfqDropObject(na);
}
if (!na || !sn) {
DropQueue();
break;
}
else {
sn->flags = XQSITE_UNREAD;
}
}
error = MatchNext(ap);
}
switch (error) {
case ERROR_NO_MORE_ENTRIES:
QueueScanned = TRUE;
break;
case 0:
Error(XQERROR_NOMEM);
break;
default:
Error(XQERROR_DOS);
break;
}
MatchEnd(ap);
}
CurrentDir(oldLock);
if (ap) {
FreeObject(ap);
}
if (vl) {
DropVarList(vl);
}
UnLock(cdLock);
}
void ReadConfig(void)
/*
* Does: Reads the configuration file. At the moment, the file name
* is XFERQ:hostaddr and contains the default domain and zone in
* the form domain#zone.
*/
{
BPTR fh;
char line[40];
struct NetAddress *na;
na = NULL;
fh = Open("XFERQ:hostaddr", MODE_OLDFILE);
if (fh) {
if (FGets(fh, line, sizeof(line))) {
line[strlen(line) - 1] = '\0';
DefaultAddr = XfqGetAddressTags(line, NULL,
XQ_Mandatory, XQADDR_2D,
XQ_Optional, XQADDR_FIDO,
TAG_DONE);
}
Close(fh);
}
ConfigRead = TRUE;
}